/*
 * Canvas Game Library
 * Module: Image
 * 
 * Copyright Chainsawrus Wreaks 2011
 * All rights reserved.
 */

/**
 * @fileOverview This is the class that handles all the graphics derived from images. It gives the developer
 * the methods to load and manipulate imagedata as well as giving the user animation possibilites.
 */

/**
 * Image module namespace
 * @namespace CGL.image
 */
CGL.image = {
		
	SCALE_NEAREST : 1,
	SCALE_LINEAR : 2,
	
	Image : function(){
		var image = {
			image : new Image(),
			loaded : false,
			useAlpha : false,
			alpha : 1.0,
			
			load : function(src) {
				CGL.resources.addImageResource();
				this.image.addEventListener("load", this.loaded, false);
				this.image.src = src;
			},
			
			loaded : function() {
				this.loaded = true;
				CGL.resources.notifyLoadedImage();
			},
			
			generateData : function() {
				var imgdata;
				var tempcanvas = document.createElement("canvas");
				var tempcontext;
				
				tempcanvas.width = this.image.width;
				tempcanvas.height = this.image.height;
				
				tempcontext = tempcanvas.getContext("2d");
				
				tempcontext.drawImage(image.image, 0, 0);
				
				imgdata = tempcontext.getImageData(0, 0, tempcanvas.width, tempcanvas.height);
				return imgdata.data;
			},

			render : function(ctx, x, y) {
				if(this.useAlpha)
				{
					ctx.globalAlpha = this.alpha;
				}
				if(this.loaded)
				{
					ctx.drawImage(this.image, x.toFixed(), y.toFixed());
				}
				if(this.useAlpha)
				{
					ctx.globalAlpha = 1.0;
				}
			},
			
			renderScaled : function(ctx, x, y, scale) {
				ctx.drawImage(this.image, x.toFixed(), y.toFixed(), this.image.width * scale, this.image.height * scale);
			},
			
			renderSpec : function(ctx, srcx, srcy, srcwidth, srcheight, destx, desty, destwidth, destheight) {
				if(this.useAlpha)
				{
					ctx.globalAlpha = this.alpha;
				}
				ctx.drawImage(this.image, srcx, srcy, srcwidth, srcheight, destx, desty, destwidth, destheight);
				if(this.useAlpha)
				{
					ctx.globalAlpha = 1.0;
				}
			},
			
			setAlpha : function(alpha) {
				this.alpha = alpha;
				if(alpha != 1.0)
				{
					this.useAlpha = true;
				}
				else
				{
					this.useAlpha = false;
				}
			}
		};
		return image;
	},
	
	SpriteSheet : function(srcw, srch, srcwidth, srcheight)
	{
		ss = {
			image : new Image(),
			width : srcw,
			height : srch,
			imgWidth : srcwidth,
			imgHeight : srcheight,
			xImg : (srcwidth / srcw),
			yImg : (srcheight / srch),
			loaded : false,
			
			load : function(src) {
				CGL.resources.addImageResource();
				this.image.addEventListener("load", this.onLoad, false);
				this.image.src = src;
			},
			
			onLoad : function() {
				this.loaded = true;
				CGL.util.printLn("Whatta Fuck!? " + this.xImg + " " + this.yImg);
				CGL.resources.notifyLoadedImage();
			},
			
			loadFromImage : function(img) {
				this.image = img.image;
				this.loaded = true;
			},
			
			render : function(ctx, x, y, i) {
				var srcX, srcY;
				if(i % this.xImg == 0)
				{
					srcY = i / this.xImg;
					srcX = this.xImg;
					srcY--;
					srcX--;
				}
				else
				{
					srcY = Math.floor(i / this.xImg);
					srcX = i % this.xImg;
					srcX--;
				}
				
				ctx.drawImage(this.image, srcX * this.width, srcY * this.height, this.width, this.height, x, y, this.width, this.height);
			}
		};
		return ss;
	},

	/**
	 * Multiply method - multiplies the image with the colors specified as parameter.
	 * @description multiply
	 * @param img - The Image that will go through the multiplication operation.
	 * @param color - The color to multiply with the image.
	 * @return the Image with new colors.
	 */
	multiply : function(img, color){
		var canvas, context, result, data;
		result = new CGL.image.Image();
		canvas = document.createElement("canvas");
		canvas.height = img.image.height;
		canvas.width = img.image.height;
		
		context = canvas.getContext("2d");
		
		context.drawImage(img.image, 0, 0);
		
		data = context.getImageData(0, 0, canvas.width, canvas.height);
		
		for(var i = 0; i < data.data.length; i += 4)
		{
			data.data[i] = (color.r * (data.data[i] / 255)) * 255;
			data.data[i+1] = (color.g * (data.data[i+1] / 255)) * 255;
			data.data[i+2] = (color.b * (data.data[i+2] / 255)) * 255;
		}
		context.putImageData(data, 0, 0);
		result.image = canvas;
		
		return result;
	},
	
	darken : function(img, value) {
		var canvas, context, result, data;
		result = new CGL.image.Image();
		canvas = document.createElement("canvas");
		canvas.height = img.image.height;
		canvas.width = img.image.height;
		
		context = canvas.getContext("2d");
		
		context.drawImage(img.image, 0, 0);
		
		data = context.getImageData(0, 0, canvas.width, canvas.height);
		
		for(var i = 0; i < data.data.length; i += 4)
		{
			data.data[i] -= value;
			if(data.data[i] < 0) { data.data[i] = 0; }
			data.data[i+1] -= value;
			if(data.data[i+1] < 0) { data.data[i+1] = 0; }
			data.data[i+2] -= value;
			if(data.data[i+2] < 0) { data.data[i+2] = 0; }
		}
		context.putImageData(data, 0, 0);
		result.image = canvas;
		
		return result.image;
	},
	/**
	 * x2 method - Linearly scales the image x2 and returns the image
	 * @method x2
	 * @param img - the image to be scaled
	 * @return The scaled image.
	 */
	x2 : function(img) {
		var canvas, context, result, datasrc, datatarget;
		result = new CGL.image.Image();
		canvas = document.createElement("canvas");
		canvas.width = img.image.width * 2;
		canvas.height = img.image.height * 2;
		
		context = canvas.getContext("2d");
		datatarget = context.getImageData(0, 0, canvas.width, canvas.height);
		context.drawImage(img.image, 0, 0);
		
		datasrc = context.getImageData(0, 0, img.image.width, img.image.height);
		width = img.image.width;
		height = img.image.height;

		for (var y = 0; y < height; y++) {
	        for (var x = 0; x < width; x++) {
	        	
	            var red = datasrc.data[((width * y) + x) * 4];
	            var green = datasrc.data[((width * y) + x) * 4 + 1];
	            var blue = datasrc.data[((width * y) + x) * 4 + 2];
	            var alpha = datasrc.data[((width * y) + x) * 4 + 3];

				datatarget.data[((width * (y*4)) + (x*2)) * 4] = red;
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 1] = green;
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 2] = blue;
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 3] = alpha;
				
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 4] = red;
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 5] = green;
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 6] = blue;
				datatarget.data[((width * (y*4)) + (x*2)) * 4 + 7] = alpha;

				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4] = red;
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 1] = green;
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 2] = blue;
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 3] = alpha;
				
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 4] = red;
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 5] = green;
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 6] = blue;
				datatarget.data[(width * 8) + ((width * (y*4)) + (x*2)) * 4 + 7] = alpha;
	        }
	    }
		context.putImageData(datatarget, 0, 0);
		result.image = canvas;
		
		return result;
	},

	scale : function(img, scale, algorithm) {
		switch(algorithm) {
			case Image.SCALE_NEAREST:
				return CGL.image.nearestNeighbor(img, scale);
			break;
			case Image.SCALE_LINEAR:
				return CGL.image.linearScale(img);
			break;
			default:
				return null;
		}
	},
	
	/**
	 * @method nearestNeighbor
	 * @description A nearest neighbor method for getting that retro pixelated mood on scaled graphics!
	 * @todo Right now you can't work with scales bellow 1, I need to think of a method that does this, maybe
	 *       send such calls to the linear method by default. 
	 * @param img - The source image.
	 * @param scale - The scale ratio.
	 * @returns A nearest neighbor scaled version of the image.
	 */
	
	nearestNeighbor : function(img, scale) {
		var canvas, context, result, datasrc, datatarget, px, py, ratio;
		result = new CGL.image.Image();
		canvas = document.createElement("canvas");
		canvas.width = img.image.width * scale;
		canvas.height = img.image.height * scale;
		ratio = img.image.width / canvas.width;
		
		context = canvas.getContext("2d");
		datatarget = context.getImageData(0, 0, canvas.width, canvas.height);
		context.drawImage(img.image, 0, 0);
		
		datasrc = context.getImageData(0, 0, img.image.width, img.image.height);
		width = img.image.width;
		height = img.image.height;

		for(var i = 0; i < canvas.height; i++)
		{
			for(var j = 0; j < canvas.width; j++)
			{
				px = Math.floor(j * ratio);
				py = Math.floor(i * ratio);
				var red = datasrc.data[((py * width) + px) * 4];
				var green = datasrc.data[((py * width) + px) * 4 + 1];
				var blue = datasrc.data[((py * width) + px) * 4 + 2];
				var alpha = datasrc.data[((py * width) + px) * 4 + 3];
				
				datatarget.data[((i * canvas.width) + j) * 4] = red;
				datatarget.data[((i * canvas.width) + j) * 4 + 1] = green;
				datatarget.data[((i * canvas.width) + j) * 4 + 2] = blue;
				datatarget.data[((i * canvas.width) + j) * 4 + 3] = alpha;
			}
		}
		
		context.putImageData(datatarget, 0, 0);
		result.image = canvas;
		
		return result;
	},
	
	linearScale : function(img, scale) {
		
	}
};

CGL.image.animation = {

	Frame : function() {
		var frame = {
			image : new CGL.image.Image(),
			duration : 0,
			
			load : function(src) {
				frame.image.load(src);
			},
			
			setDuration : function(time) {
				frame.duration = time;
			},
			
			getDuration : function() {
				return frame.duration;
			},
			
			render : function(ctx, x, y, alpha) {
				frame.image.render(ctx, x, y);
			}
		};
		return frame;
	},
		
	Animation : function(){
		var animation = {
			active : true,
			activeFrame : 0,
			maxFrames : 0,
			images : new Array(),
			timeCount : 0,
			loop : true,
			pingpong : false,
				
			load : function(frames, time) {
				var temp;
					
				for(var i = 0; i < frames.length; i++)
				{
					temp = new CGL.image.animation.Frame();
					temp.load(frames[i]);
					temp.setDuration(time);
					animation.images.push(temp);
				}
				animation.maxFrames = animation.images.length - 1;
			},
				
			nextFrame : function(){
				animation.activeFrame += 1;
			
				if(animation.activeFrame > animation.maxFrames)
				{
					if(animation.loop)
					{
						animation.activeFrame = 0;
					}
					else
					{
						animation.activeFrame = 0;
						animation.active = false;
					}
				}
			},
				
			setGlobalSpeed : function(time){
				for(var i = 0; i < animation.images.length; i++)
				{
					animation.images[i].setDuration(time);
				}
			},
			
			setSpeed : function(frame, time) {
				animation.images[frame].setDuration(time);
			},
				
			setLoop : function(looping){
				animation.loop = looping;
			},
				
			setActiveFrame : function(actFrame){
				animation.activeFrame = actFrame;
			},
				
			stop : function(){
				animation.active = false;
			},
				
			start : function(){
				animation.active = true;
			},
				
			replay : function(){
				animation.activeFrame = 0;
				animation.active = true;
			},
				
			update : function(time){
				if(animation.active)
				{
					animation.timeCount += time;
				}
						
				if(animation.timeCount > animation.images[animation.activeFrame].getDuration())
				{
					animation.nextFrame();
					animation.timeCount = 0;
				}
			},
				
			render : function(ctx, x, y, alpha){
				animation.images[animation.activeFrame].render(ctx, x, y);
			}
		};
		return animation;
	}	
};